package edu.siu.math.egut.util;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * A class to store some data associated to exceptional groups. 
 * 
 * @author Joseph Hundley
 *
 */
public class EGData {
    
    /* We use the numbering for the simple roots which is used in LiE.  
     *(LiE here refers to the software package developed by Arjeh M. Cohen, Marc van Leeuwen, and Bert Lisser.
     * More information regarding LiE may be found at http://www-math.univ-poitiers.fr/~maavl/LiE/)

     *  O 2
        |
        |
O---O---O---O---O---O---O
1   3   4   5   6   7   8   
E8


        O 2
        |
        |
O---O---O---O---O
1   3   4   5   6   
E6


        O 2
        |
        |
O---O---O---O---O---O
1   3   4   5   6   7   
E7

O---O=>=O---O
1   2   3   4   
F4

  3
O=<=O
1   2
G2


     * 
     */
    
// list of positive roots of E6 expressed as sextuples of integers in terms of the basis of simple roots.
    // One could get the same list by typing "pos_roots( E6 )" into LiE.  The order here is slightly different.
    // TODO check whether what is going on here is that this is the order in Gilkey and Seitz.
    private final static int[][] E6roots = { { 1, 0, 0, 0, 0, 0 },
    { 0, 1, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0 },
    { 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 1 }, { 1, 0, 1, 0, 0, 0 },
    { 0, 1, 0, 1, 0, 0 }, { 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 0 },
    { 0, 0, 0, 0, 1, 1 }, { 1, 0, 1, 1, 0, 0 }, { 0, 1, 1, 1, 0, 0 },
    { 0, 1, 0, 1, 1, 0 }, { 0, 0, 1, 1, 1, 0 }, { 0, 0, 0, 1, 1, 1 },
    { 1, 1, 1, 1, 0, 0 }, { 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 },
    { 0, 1, 0, 1, 1, 1 }, { 0, 0, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0 },
    { 1, 0, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1 }, { 0, 1, 1, 2, 1, 0 },
    { 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 2, 1, 0 }, { 0, 1, 1, 2, 1, 1 },
    { 1, 1, 1, 2, 1, 1 }, { 1, 1, 2, 2, 1, 0 }, { 0, 1, 1, 2, 2, 1 },
    { 1, 1, 2, 2, 1, 1 }, { 1, 1, 1, 2, 2, 1 }, { 1, 1, 2, 2, 2, 1 },
    { 1, 1, 2, 3, 2, 1 }, { 1, 2, 2, 3, 2, 1 } };
 // list of positive roots of E7 expressed as septuples of integers in terms of the basis of simple roots.
    // same order as LiE > pos_roots( E8 ) 
    private final static int[][] E7roots = { { 1, 0, 0, 0, 0, 0, 0 },
    { 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0 },
    { 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0 },
    { 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 1, 0, 0, 0 },
    { 0, 0, 1, 1, 0, 0, 0 }, { 0, 0, 0, 1, 1, 0, 0 },
    { 0, 0, 0, 0, 1, 1, 0 }, { 0, 0, 0, 0, 0, 1, 1 },
    { 1, 0, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 0, 0, 0 },
    { 0, 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1, 0, 0 },
    { 0, 0, 0, 1, 1, 1, 0 }, { 0, 0, 0, 0, 1, 1, 1 },
    { 1, 1, 1, 1, 0, 0, 0 }, { 1, 0, 1, 1, 1, 0, 0 },
    { 0, 1, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 1, 1, 0 },
    { 0, 0, 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 1, 1, 1 },
    { 1, 1, 1, 1, 1, 0, 0 }, { 1, 0, 1, 1, 1, 1, 0 },
    { 0, 1, 1, 2, 1, 0, 0 }, { 0, 1, 1, 1, 1, 1, 0 },
    { 0, 1, 0, 1, 1, 1, 1 }, { 0, 0, 1, 1, 1, 1, 1 },
    { 1, 1, 1, 2, 1, 0, 0 }, { 1, 1, 1, 1, 1, 1, 0 },
    { 1, 0, 1, 1, 1, 1, 1 }, { 0, 1, 1, 2, 1, 1, 0 },
    { 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 2, 2, 1, 0, 0 },
    { 1, 1, 1, 2, 1, 1, 0 }, { 1, 1, 1, 1, 1, 1, 1 },
    { 0, 1, 1, 2, 2, 1, 0 }, { 0, 1, 1, 2, 1, 1, 1 },
    { 1, 1, 2, 2, 1, 1, 0 }, { 1, 1, 1, 2, 2, 1, 0 },
    { 1, 1, 1, 2, 1, 1, 1 }, { 0, 1, 1, 2, 2, 1, 1 },
    { 1, 1, 2, 2, 2, 1, 0 }, { 1, 1, 2, 2, 1, 1, 1 },
    { 1, 1, 1, 2, 2, 1, 1 }, { 0, 1, 1, 2, 2, 2, 1 },
    { 1, 1, 2, 3, 2, 1, 0 }, { 1, 1, 2, 2, 2, 1, 1 },
    { 1, 1, 1, 2, 2, 2, 1 }, { 1, 2, 2, 3, 2, 1, 0 },
    { 1, 1, 2, 3, 2, 1, 1 }, { 1, 1, 2, 2, 2, 2, 1 },
    { 1, 2, 2, 3, 2, 1, 1 }, { 1, 1, 2, 3, 2, 2, 1 },
    { 1, 2, 2, 3, 2, 2, 1 }, { 1, 1, 2, 3, 3, 2, 1 },
    { 1, 2, 2, 3, 3, 2, 1 }, { 1, 2, 2, 4, 3, 2, 1 },
    { 1, 2, 3, 4, 3, 2, 1 }, { 2, 2, 3, 4, 3, 2, 1 } };
    
    // Cartan Matrix of E8 
    private final static int[][] e8Cartan = { { 2, 0, -1, 0, 0, 0, 0, 0 },
    { 0, 2, 0, -1, 0, 0, 0, 0 }, { -1, 0, 2, -1, 0, 0, 0, 0 },
    { 0, -1, -1, 2, -1, 0, 0, 0 }, { 0, 0, 0, -1, 2, -1, 0, 0 },
    { 0, 0, 0, 0, -1, 2, -1, 0 }, { 0, 0, 0, 0, 0, -1, 2, -1 },
    { 0, 0, 0, 0, 0, 0, -1, 2 } };
 // list of positive roots of E8 expressed as octuples of integers in terms of the basis of simple roots.
    // same order as LiE > pos_roots( E8 )
   private final static int[][] E8roots = {
    
    { 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1 },
            { 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 1, 0, 1, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 1, 0, 0, 0 },
            { 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0 },
            { 0, 0, 0, 0, 0, 0, 1, 1 }, { 1, 0, 1, 1, 0, 0, 0, 0 },
            { 0, 1, 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 1, 1, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 1, 1, 1, 0, 0 },
            { 0, 0, 0, 0, 1, 1, 1, 0 }, { 0, 0, 0, 0, 0, 1, 1, 1 },
            { 1, 1, 1, 1, 0, 0, 0, 0 }, { 1, 0, 1, 1, 1, 0, 0, 0 },
            { 0, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 0, 1, 1, 1, 0, 0 },
            { 0, 0, 1, 1, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 1, 0 },
            { 0, 0, 0, 0, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 0, 0 },
            { 1, 0, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 2, 1, 0, 0, 0 },
            { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 1, 1, 1, 0 },
            { 0, 0, 1, 1, 1, 1, 1, 0 }, { 0, 0, 0, 1, 1, 1, 1, 1 },
            { 1, 1, 1, 2, 1, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 0, 0 },
            { 1, 0, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 2, 1, 1, 0, 0 },
            { 0, 1, 1, 1, 1, 1, 1, 0 }, { 0, 1, 0, 1, 1, 1, 1, 1 },
            { 0, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 2, 2, 1, 0, 0, 0 },
            { 1, 1, 1, 2, 1, 1, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1, 0 },
            { 1, 0, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 2, 2, 1, 0, 0 },
            { 0, 1, 1, 2, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1 },
            { 1, 1, 2, 2, 1, 1, 0, 0 }, { 1, 1, 1, 2, 2, 1, 0, 0 },
            { 1, 1, 1, 2, 1, 1, 1, 0 }, { 1, 1, 1, 1, 1, 1, 1, 1 },
            { 0, 1, 1, 2, 2, 1, 1, 0 }, { 0, 1, 1, 2, 1, 1, 1, 1 },
            { 1, 1, 2, 2, 2, 1, 0, 0 }, { 1, 1, 2, 2, 1, 1, 1, 0 },
            { 1, 1, 1, 2, 2, 1, 1, 0 }, { 1, 1, 1, 2, 1, 1, 1, 1 },
            { 0, 1, 1, 2, 2, 2, 1, 0 }, { 0, 1, 1, 2, 2, 1, 1, 1 },
            { 1, 1, 2, 3, 2, 1, 0, 0 }, { 1, 1, 2, 2, 2, 1, 1, 0 },
            { 1, 1, 2, 2, 1, 1, 1, 1 }, { 1, 1, 1, 2, 2, 2, 1, 0 },
            { 1, 1, 1, 2, 2, 1, 1, 1 }, { 0, 1, 1, 2, 2, 2, 1, 1 },
            { 1, 2, 2, 3, 2, 1, 0, 0 }, { 1, 1, 2, 3, 2, 1, 1, 0 },
            { 1, 1, 2, 2, 2, 2, 1, 0 }, { 1, 1, 2, 2, 2, 1, 1, 1 },
            { 1, 1, 1, 2, 2, 2, 1, 1 }, { 0, 1, 1, 2, 2, 2, 2, 1 },
            { 1, 2, 2, 3, 2, 1, 1, 0 }, { 1, 1, 2, 3, 2, 2, 1, 0 },
            { 1, 1, 2, 3, 2, 1, 1, 1 }, { 1, 1, 2, 2, 2, 2, 1, 1 },
            { 1, 1, 1, 2, 2, 2, 2, 1 }, { 1, 2, 2, 3, 2, 2, 1, 0 },
            { 1, 2, 2, 3, 2, 1, 1, 1 }, { 1, 1, 2, 3, 3, 2, 1, 0 },
            { 1, 1, 2, 3, 2, 2, 1, 1 }, { 1, 1, 2, 2, 2, 2, 2, 1 },
            { 1, 2, 2, 3, 3, 2, 1, 0 }, { 1, 2, 2, 3, 2, 2, 1, 1 },
            { 1, 1, 2, 3, 3, 2, 1, 1 }, { 1, 1, 2, 3, 2, 2, 2, 1 },
            { 1, 2, 2, 4, 3, 2, 1, 0 }, { 1, 2, 2, 3, 3, 2, 1, 1 },
            { 1, 2, 2, 3, 2, 2, 2, 1 }, { 1, 1, 2, 3, 3, 2, 2, 1 },
            { 1, 2, 3, 4, 3, 2, 1, 0 }, { 1, 2, 2, 4, 3, 2, 1, 1 },
            { 1, 2, 2, 3, 3, 2, 2, 1 }, { 1, 1, 2, 3, 3, 3, 2, 1 },
            { 2, 2, 3, 4, 3, 2, 1, 0 }, { 1, 2, 3, 4, 3, 2, 1, 1 },
            { 1, 2, 2, 4, 3, 2, 2, 1 }, { 1, 2, 2, 3, 3, 3, 2, 1 },
            { 2, 2, 3, 4, 3, 2, 1, 1 }, { 1, 2, 3, 4, 3, 2, 2, 1 },
            { 1, 2, 2, 4, 3, 3, 2, 1 }, { 2, 2, 3, 4, 3, 2, 2, 1 },
            { 1, 2, 3, 4, 3, 3, 2, 1 }, { 1, 2, 2, 4, 4, 3, 2, 1 },
            { 2, 2, 3, 4, 3, 3, 2, 1 }, { 1, 2, 3, 4, 4, 3, 2, 1 },
            { 2, 2, 3, 4, 4, 3, 2, 1 }, { 1, 2, 3, 5, 4, 3, 2, 1 },
            { 2, 2, 3, 5, 4, 3, 2, 1 }, { 1, 3, 3, 5, 4, 3, 2, 1 },
            { 2, 3, 3, 5, 4, 3, 2, 1 }, { 2, 2, 4, 5, 4, 3, 2, 1 },
            { 2, 3, 4, 5, 4, 3, 2, 1 }, { 2, 3, 4, 6, 4, 3, 2, 1 },
            { 2, 3, 4, 6, 5, 3, 2, 1 }, { 2, 3, 4, 6, 5, 4, 2, 1 },
            { 2, 3, 4, 6, 5, 4, 3, 1 }, { 2, 3, 4, 6, 5, 4, 3, 2 } };
   
   /* An integral matrix of structure constants for F4.  
    *  TODO:  appears that structure constant for 1000, 1342 is -1.  I believe 
    *  that this is inconsistent with Gilkey and Seitz and may reflect an error.
    */   
    private final static int[] f4Byte =
    
    { 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1,
            0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0,
            1, -1, -2, 0, -2, -1, 0, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, -2, 0, 0,
            0, 0, -1, 0, -1, 0, -1, -2, 0, -1, 0, -2, -1, 0, -2, 0, -1, 0, 0,
            0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
            2, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 2, 0, 0, 0, -1, -2, 0, 0,
            -2, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, -1, 0, 1, 0, 0, 1, 0, 0, 0,
            0, 0, 0, -2, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, -2, 0, 0, 0, 0,
            0, 1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0,
            1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0,
            0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    
    // the Cartan matrix of F4
    private final static int[][] f4Cartan = { { 2, -1, 0, 0 },
    { -1, 2, -2, 0 }, { 0, -1, 2, -1 }, { 0, 0, -1, 2 } };
    
    /* Roots of F4 come in two lengths.  One may normalize so that the short
     * roots have length 1.  Then the long roots have length \sqrt{2}.  With this 
     * accomplished, and with a numbering of the positive roots themselves 
     * accomplished by F4roots below, F4NormSquares[i] =  | F4roots[i] |^2.   
     * 
     */
    private final static int[] F4NormSquares = { 2, 2, 1, 1, 2, 1, 1, 1, 1, 2,
    1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2 };
    
    // positive roots of F4. (slightly different order from LiE> pos_roots( G2)).
    private final static int[][] F4roots = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 },
    { 0, 0, 1, 0 }, { 0, 0, 0, 1 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 },
    { 0, 0, 1, 1 }, { 1, 1, 1, 0 }, { 0, 1, 1, 1 }, { 0, 1, 2, 0 },
    { 0, 1, 2, 1 }, { 1, 1, 1, 1 }, { 1, 1, 2, 0 }, { 0, 1, 2, 2 },
    { 1, 1, 2, 1 }, { 1, 2, 2, 0 }, { 1, 1, 2, 2 }, { 1, 2, 2, 1 },
    { 1, 2, 2, 2 }, { 1, 2, 3, 1 }, { 1, 2, 3, 2 }, { 1, 2, 4, 2 },
    { 1, 3, 4, 2 }, { 2, 3, 4, 2 } };
    
    // matrix of the normalized Weyl-Invariant inner product of F4 in terms of 
    // the basis of simple roots.
    private final static int[][] f4WIIP = { { 4, -2, 0, 0 }, { -2, 4, -2, 0 },
    { 0, -2, 2, -1 }, { 0, 0, -1, 2 } };
    
    /* integral matrix of structure constants for G2. 
     * exploiting skew-symmetry, we store only the entries above the diagonal, 
     * and we store them as a vector.
     */
    private final static int[] g2Byte = { 1, 2, 3, 0, 0, 0, 0, 1, 0, -3, 0, 0,
    0, 0, 0 };
    
    // Cartan matrix of G2
    private final static int[][] g2Cartan = { { 2, -1 }, { -3, 2 } };
    
    /* Roots of G2 come in two lengths.  One may normalize so that the short
     * roots have length 1.  Then the long roots have length \sqrt{3}.  With this 
     * accomplished, and with a numbering of the positive roots themselves 
     * accomplished by G2roots below, G2NormSquares[i] =  | G2roots[i] |^2.   
     * 
     */
     private final static int[] G2NormSquares = { 1, 3, 1, 1, 3, 3 };
     
     // positive roots of G2 in terms of the basis of simple roots. (same order as LiE> pos_roots( G2) .) 
    private static final int[][] G2roots = { { 1, 0 }, { 0, 1 }, { 1, 1 },
    { 2, 1 }, { 3, 1 }, { 3, 2 } };
    
    /* matrix of normalized Weyl-invariant inner product for G2
     *  in terms of the basis of simple roots.
     */
    private final static int[][] g2WIIP = { { 2, -3 }, { -3, 6 } };
    
    
     /**
      * Returns the list of positive roots for the unique simple exceptional group of the specified rank,
      * or null if a rank other than 2,4,6,7,8 is passed.
     * @param rank an integer, should equal 2,4,6,7, or 8. 
     * @return the list of positive roots of G2 if rank =2, and so on, or null.
     */
    public static final int[][] positiveRoots( final int rank ){
	if(rank == 2)
	    return G2roots;
	if( rank == 4)
	    return F4roots;
	if( rank == 6)
	    return E6roots;
	if( rank == 7)
	    return E7roots;
	if( rank == 8 )
	    return E8roots;
	else
	    return null;
	
	
    }
    
    
    /**
     * The Cartan matrix of the unique simple exceptional group of the specified rank.
     * A runtime exception will be thrown if this method is passed an integer other than 
     * 2,4,6,7 or 8.
     * 
     * @param rank an integer.  Must equal 2,4,6,7 or 8.
     * @return the Cartan matrix of the unique simple exceptional group of the specified rank.
     */
    public static int[][] cartan( int rank )
    {
	
	
	   
	if (rank >= 6) {
	    int[][] ourCartan = new int[rank][rank];
	    // we exploit the fact that the Cartan matrices of E6 and E7 are
	    // submatrices of that of E8
	    for (int i = 0; i < rank; i++)
		for (int j = 0; j < rank; j++)
		    ourCartan[i][j] = e8Cartan[i][j]; // 
	    return ourCartan;

	} else if (rank == 4) {
	    return   f4Cartan;

	} else if (rank == 2) {
	    return g2Cartan;
	} else
	    throw new RuntimeException();// This should only be used on the
	// five
	// Exceptional groups
    }
    /**
     * The matrix of the normalized Weyl-invariant inner product in terms of the 
     * basis of simple roots.
     * 
     * A runtime exception will be thrown if this method is called with an argument other than
     * 2,4,6,7 or 8.
     * 
     * @param rank and integer, which must equal 2,4,6,7, or 8.
     * @return The matrix of the normalized Weyl-invariant inner product in terms of the 
     * basis of simple roots.
     */
    public static int[][] weylInvtInnProd( int rank){
	   
	if (rank >= 6) {
	    return cartan( rank);	    // For simply laced groups the normalized Weyl invariant inner
	    // product is
	    // given by the Cartan matrix.

	} else if (rank == 4) {
	    return f4WIIP;

	} else if (rank == 2) {
	    return g2WIIP;
	} else
	    throw new RuntimeException();// This should only be used on the
	// five
	// Exceptional groups
    }
    /**
     * An integral matrix of structure constants for the unique exceptional Lie algebra of the specified rank
     * @param rank must equal 2, 4, 6, 7 or 8 
     * @return matrix of structure constants, either from a data file, or by implementing the algorithm 
     * described in the paper of Gilkey and Seitz 
     * 		Some representations of exceptional Lie groups, Geom. Dedicata 25 (1998) 407-416.
     */
   public static StructureConstantsMatrix structureConstantsMatrix( int rank)
   {
	   
	if (rank >= 6) {
	    return gilkeySeitz( new VectorCayleyTable( positiveRoots(rank)), rank);

	} else if (rank == 4) {
	    return new StructureConstantsMatrix(F4roots, f4Byte, 24);

	} else if (rank == 2) {
	    return new StructureConstantsMatrix(G2roots, g2Byte, 6);
	} else
	    throw new RuntimeException();// This should only be used on the
	// five
	// Exceptional groups

   }
   
   /**
    * A vector which contains the values of |alpha|^2, where alpha ranges over the positive roots of the 
    * unique simple exceptional group of the desired rank, in the order fixed above
    * and | | is the norm, defined using the Weyl-invariant inner product normalized so that the short roots have length 1.
    * 
    * If this method is called with an argument other than 2,4,6,7 or 8, a runtime exception will result.
 
 * 
 * @param rank an integer.  Should equal 2,4,6,7, or 8.
 * @return list of norm squares of simple roots.
 */
public static int[] normSquares( int rank ){
    /* If rank = 2 or 4, we stored this data above.
     * 
     */
       if( rank == 2)
	   return G2NormSquares;
       if( rank == 4)
	   return F4NormSquares;
       
       // if rank is not in { 2,4,6,7,8}, calling positiveRoots(rank) will result in a 
       // runtime exception.
       int[] answer = new int[positiveRoots(rank).length];
       
// if rank = 6, 7 or 8, then all the roots are the same length, which was normalized to be 1.
   Arrays.fill(answer, 1);
   return answer;
   }
   
   /**
    * Method for generating the matrix of structure constants for the
    * exceptional groups E6, E7, and E8.  This method uses the method given in 
    * P. Gilkey, G. Seitz, Some representations of exceptional Lie groups,
    *	Geom. Dedicata 25 (1998) 407-416.
    * which means that for each root \beta the structure constant N(\alpha_i, \beta-\alpha_i) is 
    * defined to be one for the smallest integer i such that \beta-\alpha_i is a root.  (Here \alpha_i is 
    * a simple root, and the numbering is as above.)  This in effect determines a basis for the one-dimensional
    * Lie subalgebra corresponding to \beta and permits all other structure constants to be computed.
    * 
    * REMARK:  we use this method only for the simply laced groups E6,E7, E8.  It can be modified 
    * for use with F4 and G2, but the value of N(\alpha_i, \beta-\alpha_i) can not be one in all cases,
    * if one wants all structure constants to remain integral.
    * 
    * @param additionTable the Cayley table for the positive roots of a root system
    * @param rank the rank of the exceptional group (valid choices are 6, 7, and
    *            8)
    * @return the matrix containing the structure constants
    */
   private static StructureConstantsMatrix gilkeySeitz(VectorCayleyTable additionTable,
	    final int rank) {
       
       // instantiate a new structure constants matrix.
	StructureConstantsMatrix matrix = new StructureConstantsMatrix(
		positiveRoots(rank), additionTable.length);
	int[][] z = additionTable.getRoots();

	// Phase I: sums of the form \alpha_i + \beta
	
	// we maintain a list of all roots \gamma which have already been obtained as sums.
	Set<int[]> found = new HashSet<int[]>();
	
	for (int i = 0; i < rank; i++) { // the simple roots are z[0] to z[ rank - 1].  \alpha_i = z[i-1].
	    for (int j = (i + 1); j < additionTable.length; j++) {
		
		// add the roots using the table.  This returns "null" if the sum of the 
		// two tuples does not correspond to a root.
		int[] sum = additionTable.add(z[i], z[j]);
		
		if (sum != null && !found.contains(sum)) { // that is, if \alpha_{i+1}+\beta is a root, 
		    //and i is the least integer 
		    // with this property
		    found.add(sum);// we add the sum to the list of roots \gamma that have been found.
		    matrix.set(i, j, 1);// and we set the relevant structure constant to 1.
		}
	    }
	}

	// Phase II: a+b
	for (int i = 0; i < additionTable.length - 1; i++) {
	    for (int j = (i + 1); j < additionTable.length; j++) { // by skew-symmetry one may assume i<j.
		
		// compute the sum with the table.
		int[] sum = additionTable.add(z[i], z[j]);
		
		// if the result is null, this is not a root.  the relevant structure constant is defined to be 0.
		if (sum != null && matrix.get(z[i], z[j]) == 0) {
		    // now, if the sum is a root and yet the value in the matrix is zero, then we have something to do.
		    
		    // find the smallest integer min such that our sum may be expressed as \alpha_{min+1} + \beta.
		    int min = minI(additionTable, rank, sum);
		    
		    // the corresponding simple root is z[min]
		    
		    // now either z[i] - z[min] or z[j] - z[min] is a root
		    int[] k = additionTable.subtract(z[i], z[min]);
		    
		    if (k != null) { // i.e., if z[i]-z[min] is a root...
			matrix.set(i, j, // then  N(z[i], z[j] ) = N(z[min], z[i]-z[min])*N(z[i]-z[min],z[j])
			(matrix.get(z[min], k)
			* matrix.get(k, z[j])));
		    } else { // then z[j]-z[min] will be a root.
			k = additionTable.subtract(z[j], z[min]);
			matrix.set(i, j, (-1 * matrix.get(z[min], k) * matrix
				.get(k, z[i])));// and N(z[i],z[j]) = - N(z[j]-z[min], z[i]) N(z[min], z[j]-z[min]) 
		    }
		    /* The formulae used just above are taken from p. 410 of the paper of Gilkey and Seitz  
		     * (with some misprints corrected).  They can be derived from formulae (1)-(6) on 
		     * the previous page of the same paper.  
		     * 
		     * The careful reader will note that this algorithm will only perform correctly provided 
		     * that N(z[min], z[i]-z[min]) and N(z[i]-z[min],z[j]) in the "if" case, 
		     * or N(z[j]-z[min], z[i]) and N(z[min], z[j]-z[min]) in the "else" case,
		     * have both been initialized before the attempt is made to initialize N(z[i],z[j]).
		     * 
		     * It is clear that there is no issue with N(z[min], z[i]-z[min]) or N(z[min], z[j]-z[min]),
		     * since these constants were initialized at Phase I.  The point, then, is  that
		     * \alpha always comes before \alpha+ \alpha_i in the ordering which we have fixed 
		     * on the roots, whenever both are roots.
		     * 
		     *
		     */
		    

		}
	    }
	}

	return matrix;
   }



/**
 * Used in the Gilkey-Seitz algorithm for determining structure constants implemented in gilkeySeitz.
 * 
 * This method computes and returns the minimal integer i such that the given root may be expressed as 
 * \alpha_i + \beta.
 * 
 */
private static int minI(VectorCayleyTable roots, final int rank, int[] root) {
	int[][] z = roots.getRoots();
	for (int i = 0; i < rank - 1; i++) {
	    for (int j = i + 1; j < roots.length; j++) {
		if (Arrays.equals(roots.add(z[i], z[j]), root))
		    return i;
	    }
	}
	return (rank - 1);
}

public static int[][] G2ReflectionSigns={{-1,1,-1,1,-1,1,-1,1,-1,1,-1,1},{-1,-1,1,1,1,-1,-1,-1,1,1,1,-1}};


}
